package com.lcp.se.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;

/**
 * 统一鉴权
 *
 * @author lcp
 * @date 2020/7/22 20:16
 */
@Component
@Slf4j
public class GlobalAuthFilter implements GlobalFilter, Ordered {

    private static final String APPLET_USER_SESSION_ID_PATH = "/user/applet/login";

    @Value("${mini-program.user-auth-info-key-redis}")
    private String authInfoKey;

    @Value("${mini-program.separator-auth}")
    private String separatorAuth;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String requestPath = exchange.getRequest().getPath().toString();
        // log.info("requestPath：" + requestPath);
        // 无条件放行登录请求
        if (requestPath.equals(APPLET_USER_SESSION_ID_PATH)) {
            return chain.filter(exchange);
        }

        // 访问测试路径
        if (requestPath.equals("/user/hello")) {
            return chain.filter(exchange);
        }

        String sessionId = null;
        String openId = null;

        // 判断请求头或请求参数中是否携带了 sessionId，openId

        // 获取参数中的 sessionId，openId
        MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
        log.info("请求参数：" + queryParams.toString());
        if (Objects.nonNull(queryParams.get("sessionId")) && Objects.nonNull(queryParams.get("openId"))) {
            sessionId = queryParams.get("sessionId").get(0);
            openId = queryParams.get("openId").get(0);
        }

        // 获取请求头中的 sessionId，openId
        HttpHeaders headers = exchange.getRequest().getHeaders();
        log.info("请求头：" + headers.toString());
        List<String> sessionIdH = headers.get("sessionId");
        List<String> openIdH = headers.get("openId");

        // 如果请求头中的 sessionId，openId 不为 null，则覆盖赋值
        if (Objects.nonNull(sessionIdH) && Objects.nonNull(openIdH)) {
            sessionId = sessionIdH.get(0);
            openId = openIdH.get(0);

        }

        // sessionId 或 openId 为空，非法请求，直接结束
        if (Objects.isNull(sessionId) || Objects.isNull(openId)) {
            log.info("非法请求，没有传递 sessionId 或 openId，请求路径：" + requestPath);
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }


        // openId 无对应的用户登录信息，非法请求，直接结束
        Object o = redisTemplate.opsForHash().get(authInfoKey, openId);
        if (Objects.isNull(o)) {
            log.info("非法请求，用户还未登录，请求路径：" + requestPath);
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }

        // 服务端存储登录信息与客户端传递的不一致，非法请求，直接结束
        if (!o.toString().split(separatorAuth)[0].equals(sessionId)) {
            log.info("非法请求，无效的 sessionId，请求路径：" + requestPath);
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }

        log.info("合法请求，请求路径：" + requestPath);
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
